﻿using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage.Streams;

namespace Microsoft.Media.IngestClient
{
    /// <summary>
    /// A class used to adapt Stream to IInputStream
    /// </summary>
    internal sealed class SequentialInputStream : IInputStream
    {
        Stream inputStream;
        uint totalBytesRead;

        internal SequentialInputStream(Stream inputStream)
        {
            this.inputStream = inputStream;
        }

        /// <inheritdoc />
        public void Dispose()
        {
            inputStream.Dispose();
        }

        /// <inheritdoc />
        public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
        {
            return AsyncInfo.Run((CancellationToken c, IProgress<uint> p) => _ReadAsync(buffer, count, options, c, p));
        }

        async Task<IBuffer> _ReadAsync(IBuffer buffer, uint count, InputStreamOptions options, CancellationToken c, IProgress<uint> progress)
        {
            var bytes = new byte[count];

            var bytesRead = await Task.Run(() =>
            {
                int totalRead = 0;
                while (totalRead < count)
                {
                    try
                    {
                        var currentBytesRead = inputStream.Read(bytes, totalRead, (int)count - totalRead);
                        c.ThrowIfCancellationRequested();
                        totalRead += currentBytesRead;
                        if (currentBytesRead == 0) break;
                    }
                    catch (System.IO.EndOfStreamException)
                    {
                        break;
                    }
                }
                return (uint)totalRead;
            }, c);

            totalBytesRead = totalBytesRead + bytesRead;
            progress.Report(totalBytesRead);
            return bytes.AsBuffer(0, (int)bytesRead);
        }
    }
}
